home *** CD-ROM | disk | FTP | other *** search
- page 60,132
- title Start_Up1 -- Intermediate Start Up Code for .EXE Programs
- name Start_Up1
-
- comment ÷
- Start_Up1 V1.05
- --------------------------------------------------------------------------
- NAME
- startup1 Intermediate start up code for .exe programs
-
- SYNOPSIS
- extern Start_Up1
- or
- extern Start_Up1S
-
- See Programming Notes below for difference.
-
- DESCRIPTION
- This is the startup code for all .exe and .com assembly language
- programs. Just use the SYNOPSIS above in the main function to
- include the startup code in the .exe file from a .lib. For .com
- assembly language programs, this source code must be the first
- assembled so that this code is the linked first.
-
- This procedure parses the command line into argc and *argv[] similar
- to C. Argv[0] is the first command line argument not the program
- name as in C.
-
- This procedure performs the following functions in addition to above
- - Initializes the following global variables:
- -- DGRP, segment address of DGROUP
- -- STACK_BOTTOM, offset to stack bottom in DGROUP
- -- PSP, segment address of PSP
- -- ENVIRON, segment address of passed copy of the ENVIRONMENT
- -- OSMAJOR, integer part of OS system
- -- OSMINOR, decimal part of OS system
- - If DOS version is less than 2.0, aborts with error message
- - Initializes DS and ES segment registers to DGROUP
- - Skrinks memory down to size of program by releasing all memory
- above program
-
- RETURNS
- If main returns to startup code. The program terminiates with the
- return code in AL.
-
- PROGRAMING NOTES
- Assembled with Microsoft MASM V6.11A.
-
- Written to link with any memory model
-
- Assemble with the following command line options to get the desired
- memory models:
-
- Command Line Memory Model
- /Dmemmod=tiny Tiny (.com file)
- /Dmemmod=small Small (default)
- /Dmemmod=compact Compact
- /Dmemmod=medium Medium
- /Dmemmod=large Large
- /Dmemmod=huge Huge
-
- Written using the FORTRAN/PASCAL/BASIC calling convention so passed
- parameters are pushed in the order of appearance in the proc
- declaration.
-
- This procedure can pass argc and argv on stack two ways. The proc
- declaration in the MAIN procedure will differ depending upon the
- choice.
-
- The default requires the following proc declaration:
-
- MAIN proc ARGC:word, ARGV:ptr
-
- If SIMPLE is defined, an alternate proc declaration is required:
-
- MAIN proc ARGV:ptr, ARGC:word
-
- Here, ARGV is not a pointer to an array of pointers but the location
- of the 1st pointer.
-
- Procedures called:
- Main
- DOS Interrupts
- Int 21h 9h - Display String
- Int 21h 30h - Get Version Number
- Int 21h 4ah - Set Memory Block Size
- Int 21h 4ch - Terminate program with return code
-
- In Huge memory model, the pointers passed in ARGV are long pointer
- vice huge pointers.
-
- MEMORY REQUIREMENTS
- (in bytes) Tiny Small Medium Compact Large Huge
- Code: 211 215 217 218 220 220
- Code (SIMPLE): 208 212 214 214 216 216
- _Data: 0 0 0 0 0 0
- Const: 14 14 14 14 14 14
- _BBS: 10 10 10 10 10 10
- Stack: ? ? ? ? ? ?
-
- The first code size is for SIMPLE not defined. The Code (SIMPLE) is
- for when SIMPLE is defined.
-
- Stack usage is determined by the size of and the number of arguments
- in the command line.
-
-
- CAUTION
- Startup1 defines a 512 byte stack. This should be enough for programs
- who make moderate use of the stack. If automatic variables are used
- extensively, more stack space should be defined in the main module.
-
- AUTHOR
- Raymond Moon - 7 Sep 87
-
- Copyright (c) 1987, 1988, 1994, 1995 - MoonWare
- ALL RIGHTS RESERVED
-
- VERSION
- Version - Date - Remarks
- 1.00 - 7 Sep 87 - Original
- 1.01 - 13 Feb 88 - Updated to program name as argv[0]
- - This created Startup1 from Startup0
- 1.02 - 4 Jul 88 - Converted to MASM V5.1
- 1.03 - 9 Oct 88 - Added Stack_Bottom & ZZ_PRGM_TOP segment
- to determine end of data.
- 1.04 - 30 Oct 94 - Moved ZZ_PRGM_TOP segment position in file.
- - Removed increment in program size in paras
- as ZZ_PRGM_TOP is aligned on a para.
- 1.05 - 5 Mar 95 - Added TINY Model capability
- - Converted to .dosseg using __end vice
- ZZ_PRGM_TOP for end of data
-
- ==========================================================================
- ÷ Commend End
-
- ;-----------------------------
- ; Make the small memory model the default
-
- ifndef memmod
- memmod equ <small>
- endif
-
- include procesor.inc
- % .MODEL memmod,FORTRAN
- assume es:DGROUP
- .dosseg
-
- ;----------------------------
- ; Required includes
-
- include stderrf.inc
-
- ;----------------------------
- ; Define any required equates
-
- STACK_SIZE equ 512
-
- ;=========================================================================
- ; DATA
- ;=========================================================================
- ; Define storage for the various global and system variables and
- ; constants.
-
- .CONST
-
- BAD_DOS_VERSION db 'Need DOS 2.0+$'
-
- .DATA?
-
- DGRP dw ? ; Value of DGROUP
- STACK_BOTTOM dw ? ; Offset to stack bottom in DGROUP
- PSP dw ? ; Segment address of PSP
- ENVIRON dw ? ; Segment address of ENVIRON
- OSMAJOR db ? ; Integer part of OS system
- OSMINOR db ? ; Decimal part of OS system
-
- if @Model NE 1
- .STACK STACK_SIZE ; Define a nominal stack
- endif
-
- @CurSeg ends
-
- ;----------------------------
- ; Define __end which is defined when using .dosseg
-
- externdef __end:byte
-
-
- ;----------------------------
- ; Define segment for addressing information in the PSP
-
- PSP_SEG segment at 00h
-
- org 2ch
- ENVIRON_PTR dw ? ; Segment address of Environment
-
- org 80h
- PARM_LEN db ? ; Number of bytes in Command Line tail
- PARMS db 127 dup(?) ; Start of Command Line tail
- PSP_SEG ends
-
- ;=========================================================================
- ; CODE
- ;=========================================================================
- ; Put the called main procedure in the proper relationship to the
- ; startup code.
-
- if @CodeSize
- extrn Main:far
- .CODE
- else
- .CODE
- extrn Main:near
- endif
-
- ;-----------------------------
- ; Include org statement if tiny model
-
- if @Model EQ 1
-
- org 100h
- endif
-
- ;-----------------------------
- ; Start the Start_Up1 code. Make it a far procedure so error return
- ; will work. If SIMPLE is defined, redefined Start_Up1 as Start_Up1S.
-
- ifdef SIMPLE
- Start_Up1 equ <Start_Up1S>
- endif
-
- % Start_Up1 proc far
-
- ;-----------------------------
- ; First, initialize global variables. Set DS to DGROUP.
-
- if @Model NE 1
- mov ax, DGROUP ; Get seg address of DGROUP
- mov ds, ax ; Initialize DS segment register
- mov DGRP, ax ; Initialize DGRP
- else
- mov DGRP, ds ; Initialize DGRP
- endif
-
- mov PSP, es ; Initialize PSP
- assume es:PSP_SEG
- mov bx, es:ENVIRON_PTR ; Get segment address of environment
- mov ENVIRON, bx ; Initialize ENVIRON
- mov ah, 30h ; Get DOS version number
- int 21h ; Call DOS
- mov OSMAJOR, al ; Save major version number
- mov OSMINOR, ah ; Save minor version number
-
- ;----------------------------
- ; If DOS version is prior to 2.0, write error message and terminate
- ; the program. The program terminates with a far call to INT 20h.
-
- cmp al, 2 ; Is the OS 2.0 below?
- jae SU1 ; No, continue
- mov ah, 9 ; DOS display string
- lea dx, BAD_DOS_VERSION ; DS:DX => string to be displayed
- int 21h ; Call DOS
- push PSP ; Push return segment
- xor ax, ax ; AX = 0
- push ax ; Push return IP
- ret ; Far return to PSP:0000
-
- ;----------------------------
- ; Combine the stack into DGROUP so that it is addressable from DGROUP.
- ; Initialize STACK_BOTTOM.
-
- SU1: lea bx, __end ; Get pointer to end of data
-
- if @Model eq 1 ; Ensure that Stack bottom at paragraph
- and bx, 0fff0h ; Truncate to lower paragraph
- add bx, 16 ; Add one paragraph
- endif
-
- mov STACK_BOTTOM, bx ; Save it
-
- if @Model eq 1 ; Get stack size
- add bx, STACK_SIZE ; DI = stack size
- else
- add bx, sp ; DI = stack size
- endif
-
- mov dx, ds ; Get DGROUP segment address
- mov ss, dx ; Reset SS
- mov sp, bx ; Reset SP
-
- ;----------------------------
- ; Release all memory above program. Calculate the size of the program
- ; in paragraphs (16 bits). BX starts with Stack Top
-
- mov cl, 4 ; Convert to #para by dividing by 16
- shr bx, cl ; Do division by bit shifting
-
- if @Model ne 1 ; Needed in non-Tiny memory models
- mov ax, ds ; AX => DGROUP
- sub ax, PSP ; AX = # para for code
- add bx, ax ; BX = # para in program
- endif
-
- mov ah, 4ah ; Request DOS set block
- int 21h ; Call DOS
-
- ;----------------------------
- ; See if there are any command line arguments. If not, all command
- ; line processing is skipped. The pushed null on the stack will be
- ; argc, and a null pointer is also pushed onto the stack so argv[0]
- ; is a null pointer.
-
- xor dx,dx ; Ensure DX is null
- push dx ; Ensure null on top of stack
- mov bp,sp ; BP = top of stack
- cmp es:PARM_LEN,0 ; Are there any Command Line arguments
- jne SU2 ; No, go process what is on the stack
- push dx ; Push null pointer
- if @DataSize
- push dx ; Make a doubleword null pointer
- endif
- mov es,DGRP ; Initialize ES
- jmp short SU10 ; Go call MAIN
-
- ;----------------------------
- ; There are command line arguments. Parse them onto the stack and
- ; build ARGC and ARGV. Start this by transferring the entire command
- ; line tail onto the stack. Make room for them by moving SP.
-
- SU2: mov cl, es:PARM_LEN ; Get # of bytes in Command Line
- inc cx ; increase by one
- and cx, 0feh ; Force an even count
- mov ax, sp ; Get SP
- sub ax, cx ; Subtract PARM_LEN
- mov sp, ax ; Reset SP, room on Stack
- lea si, es:PARMS ; Load source addr in SI
- mov di, sp ; Load destin addr in DI
- mov es, DGRP ; ES => DGROUP
- assume es:DGROUP
- mov ds, PSP ; DS => PSP
- rep movsb ; Move Command Line onto the Stack
- mov ds, es:DGRP ; Restore DS
-
- ;-----------------------------
- ; Convert all blanks, not within double quotes, in the Command Line
- ; to Nul. CX is IN_LITERAL_FLAG.
-
- mov bx, bp ; BX points to last byte in stack
- xor cx, cx ; Clear IN_LITERAL_FLAG
- SU3: mov al, [bx] ; Get byte
- cmp al, '"' ; Is it a literal?
- jne SU4 ; No, go to next test
- inc cx ; Set IN_LITERAL_FLAG
- and cx, 1 ; Ensure only 0, & 1 valid
- jmp short SU5 ; Continue, and blank '"'
- SU4: cmp al, ' ' ; Is it a blank?
- ja SU6 ; No, go set up to get another
- or cx, cx ; Is IN_LITERAL_FLAG clear?
- jne SU6 ; No, do not null blank
- SU5: xor al, al ; Nul AX
- mov [bx], al ; Store Nul in [BX]
- SU6: dec bx ; BX point to next byte
- cmp bx, sp ; Are we through yet?
- jnb SU3 ; No, go one mo' 'gin
-
- ;-----------------------------
- ; Build *argv[]. argc kept in CX. DX used as IN_WORD flag
- ; Build it backwards. CX is 0 upon entry.
-
- mov dx, cx ; Set CX (argc) to 0
- push cx ; Put a null at the start
- mov bx, bp ; BX point to last byte
- mov bp, sp ; BP now points to Top of Stack
- SU7: mov al, [bx - 1] ; Get byte
- or al, al ; Is it Nul?
- jnz SU8 ; No, it is a char
- or dx, dx ; Was the last byte not a char?
- jz SU9 ; Yes, go on with the processing
- xor dx, dx ; No, it was a char. Clear IN_WORD.
- inc cx ; Increment argc
- if @DataSize
- push ss ; Push segment address
- endif
- push bx ; Push addr onto stack
- jmp short SU9 ; Go set up for another byte
- SU8: inc dx ; Set DX to IN_WORD
- SU9: dec bx ; BX point to next byte
- cmp bx, bp ; Are we at the 1st byte yet?
- jg SU7 ; No, go process another
-
- ;-----------------------------
- ; Create argc and argv on the stack. Default is FORTRAN calling
- ; convention. If SIMPLE is defined, push only argc. See documentation
- ; above for structure of proc declaration in MAIN procedure
-
- ifndef SIMPLE
- mov bx, sp ; BX = **argv[]
- push cx ; Push argc
- if @DataSize
- push ss ; Long pointer
- endif
- push bx ; Push **argv[]
- else
- push cx ; Push argc
- endif
-
- ;-----------------------------
- ; call MAIN
-
- SU10: call Main ; Call MAIN procedure
-
- ;----------------------------
- ; If main returns, the program is to terminate with the return code
- ; returned in AL
-
- mov ah, 4ch ; End process
- int 21h ; Call DOS
-
- % Start_Up1 endp
-
- % end Start_Up1 ; Indicate that Start_Up1 is the start
- ; of the program
-